/**
 * 时间画布类
 * by littlefean
 */
class CanvasTimeTable {
    /**
     *
     * @param canvasEle canvas标签
     * @param width {Number} 整个画布宽度
     * @param height {Number} 整个画布高度
     * @param hourHeight {Number} 每一个小时的高度
     */
    constructor(canvasEle, width, height, hourHeight) {
        this.ele = canvasEle;
        this.canvasW = width;
        this.canvasH = height;
        this.hourHeight = hourHeight;

        this.weekLen = this.canvasW / 7;
        this.ctx = canvasEle.getContext("2d");
        this._touchData = {  // 有关添加属性相关的信息 只在类内部用
            touchStartLoc: {x: null, y: null},
            touchEndLoc: {x: null, y: null},
            touchWeek: NaN,
        };
        this.mood = {
            _name: 1,
            setWatching: function () {
                this._name = 1;
            },
            isWatching: function () {
                return this._name === 1
            },
            setAdding: function () {
                this._name = 2;
            },
            isAdding: function () {
                return this._name === 2
            },
            setSliding: function () {
                this._name = 3;
            },
            isSliding: function () {
                return this._name === 3;
            },
            setChoosing: function () {
                this._name = 4;
            }
        };
        this._initialize();
    }

    /**
     * 重新调整大小，用于浏览器界面大小发生变化
     * @param width {Number}
     * @param height {Number}
     * @param hourHeight {Number}
     */
    resize(width, height, hourHeight) {
        this.canvasW = width;
        this.canvasH = height;
        this.hourHeight = hourHeight;
        this.weekLen = this.canvasW / 7;
        this._canvasResize();
        // 隐患，如果当前不是watching模式，也应该强制关闭所有弹窗
        this.refresh();
    }

    _canvasResize() {
        this.ele.width = this.canvasW * PR;
        this.ele.height = this.canvasH * PR;
        this.ele.style.width = `${this.canvasW}px`;
        this.ele.style.height = `${this.canvasH}px`;
        this.ctx.translate(0.5 * PR, 0.5 * PR);
        this.clear();
        this.drawFrame();
    }

    _initialize() {
        this._canvasResize();
        // 绘制控制相关
        this._bindTouchStart();
        this._bindTouchMove();
        this._bindTouchEnd();
        // 添加时间段的按钮逻辑
        let alertAddTime = document.querySelector(`.alertAddTime`);
        let cancelAdd = alertAddTime.querySelector(`.cancelAdd`);
        // 取消添加时间段
        cancelAdd.addEventListener("click", () => {
            alertAddTime.style.display = "none";
            this.refresh();
            this.mood.setAdding();
        });
    }

    /**
     * 绑定开始绘制添加时间段的方法
     * 该方法只在构造方法中被调用
     * click事件和touch事件是冲突的
     * @private
     */
    _bindTouchStart() {
        let f = (pX, pY) => {
            this._touchData.touchStartLoc.x = pX;
            this._touchData.touchStartLoc.y = pY;
            // 当前触摸的是星期几
            this._touchData.touchWeek = Math.floor(this._touchData.touchStartLoc.x / (this.canvasW / 7));  // week [0~6]
            if (this.mood.isAdding()) {
                this.mood.setSliding();
                // 画起始线段
                drawLine(
                    this.ctx,
                    this._touchData.touchWeek * this.weekLen,
                    this._touchData.touchStartLoc.y,
                    (this._touchData.touchWeek + 1) * this.weekLen, this._touchData.touchStartLoc.y,
                    2, "red"
                );
            }
        };
        if (isPc()) {
            this.ele.addEventListener("mousedown", (e) => {
                f(e.clientX - (WIN_WIDTH * 0.1), e.clientY - 90);
            });
        } else {
            this.ele.addEventListener("touchstart", (e) => {
                // 这个减去90是提前根据css算好的了，上面的90是提前固定规划好的了
                f(e.targetTouches[0].pageX - (WIN_WIDTH * 0.1), e.targetTouches[0].pageY - 90);
            });
        }
    }

    /**
     * 该方法只在构造方法中被调用
     * @private
     */
    _bindTouchMove() {
        // 绘制拖动
        let f = (y) => {
            if (!this.mood.isSliding()) {
                return;
            }
            this.refresh();
            // 画一个矩形框
            let marginTop = Math.min(this._touchData.touchStartLoc.y, y);
            let height = Math.abs(this._touchData.touchStartLoc.y - y);
            drawRectStroke(this.ctx, this.weekLen * this._touchData.touchWeek, marginTop, this.weekLen, height, "red", 3);
            drawRectFill(this.ctx, this.weekLen * this._touchData.touchWeek, marginTop, this.weekLen, height, `rgba(255, 0, 0, 0.3)`);
            // 画移动的当前水平线
            drawLine(this.ctx, 0, y, this.canvasW, y);
        }
        if (isPc()) {

            this.ele.addEventListener("mousemove", (e) => {
                // let pX = e.clientX - (WIN_WIDTH * 0.1);
                let pY = e.clientY - 90;
                f(pY);
                // 更改鼠标形状
                if (this.mood.isWatching()) {
                    // let p = this._findPeriodByLoc(pX, pY);
                    // if (p === null) {
                    //     this.ele.style.cursor = "pointer";
                    // } else {
                    this.ele.style.cursor = "help";
                    // }
                } else if (this.mood.isAdding()) {
                    this.ele.style.cursor = "crosshair";
                }
            })

        } else {
            this.ele.addEventListener("touchmove", (e) => {
                // 这个减去90是提前根据css算好的了，上面的90是提前固定规划好的了
                f(e.targetTouches[0].pageY - 90);
            });
        }
    }

    /**
     * 寻找一个用户的时间段对象 通过用户点击的xy坐标像素
     * @param x
     * @param y
     * @private
     */
    _findPeriodByLoc(x, y) {
        let date = NOW_WEEK[this._touchData.touchWeek];
        for (let p of USER_DATA.periodList) {
            if (p.date === date) {
                // 如果刚好是这一天的，就看看是不是点到这个了
                if (p.pxRangeIn(this._touchData.touchEndLoc.y, this.canvasH)) {
                    // 找到了要点击的时间段
                    return p;
                }
            }
        }
        return null;
    }

    /**
     * 该方法只在构造方法中被调用
     * @private
     */
    _bindTouchEnd() {
        let pX, pY;
        let f = () => {
            this._touchData.touchEndLoc.x = pX;
            this._touchData.touchEndLoc.y = pY;
            if (this.mood.isWatching()) {
                let p = this._findPeriodByLoc();
                if (p === null) {
                    Bubble.pop("观看模式未点击对象");
                    alertDiv($(".modeChangeBtn"), "note");
                    return;
                }
                // 点击一个时间段，会弹出这个时间段的属性界面
                // 弹出一个框，展示这个时间段的信息
                let panelEle = document.querySelector(`.alertModifyTime`);
                setTimeout(() => {  // 防止手在这个框上面松开
                    panelEle.style.display = "block";
                }, 100);
                panelEle.querySelector(".name").innerHTML = p.obj.name;
                panelEle.querySelector(".startTime").innerHTML = p.start;
                panelEle.querySelector(".durTime").innerHTML = p.dur;
                // 设置这个弹窗的其他按钮
                let delEle = panelEle.querySelector(`.delThis`);
                delEle.onclick = () => {
                    // 将这个时间段删除 告诉后端我删除了一个时间段
                    AJAX("userDelPeriod", {
                        userName: USER_DATA.name,
                        period: JSON.parse(p.toString())
                    }).finish(res => {
                        USER_DATA.delPeriod(p);
                        this.refresh();
                    })
                    // 关闭面板
                    panelEle.style.display = "none";
                }
                let cancelModify = panelEle.querySelector(`.cancelModify`);
                cancelModify.onclick = function () {
                    panelEle.style.display = "none";
                }
            } else if (this.mood.isSliding()) {
                if (Math.abs(this._touchData.touchStartLoc.y - this._touchData.touchEndLoc.y) < 4) {
                    Bubble.pop("请按住并拖出一段距离");
                    alertDiv($(".modeChangeBtn"), "note");
                    this.mood.setAdding();
                    this.refresh();
                    return;
                }
                this.mood.setChoosing();
                // 触发添加段的功能  先弹出框
                let alertWindow = document.querySelector(`.alertAddTime`);
                setTimeout(() => {
                    alertWindow.style.display = "block";
                }, 100);
                // 更新弹出框里面的选择
                let addMenu = document.querySelector(`.addMenu`);
                addMenu.innerHTML = "";
                for (let kind of USER_DATA.addTimeKindList) {
                    let kindDiv = div(kind.name, "kind");
                    kindDiv.style.backgroundColor = kind.color;
                    kindDiv.style.color = kind.fontColor;

                    kindDiv.onclick = () => {
                        // 添加事件
                        let p = TimePeriod.InfoTo(
                            this.canvasH,
                            this._touchData.touchStartLoc.y,
                            this._touchData.touchEndLoc.y,
                            this._touchData.touchWeek.toString(),
                            NOW_WEEK[this._touchData.touchWeek]
                        );
                        p.setStyle(kind);
                        USER_DATA.periodList.push(p);
                        // 发送给后端添加
                        AJAX("userAddPeriod", {
                            userName: USER_DATA.name,
                            period: JSON.parse(p.toString())
                        }).finish(res => {
                            if (res === "ok") {
                                alertWindow.style.display = "none";
                                this.refresh();
                                this.mood.setAdding();
                            }
                        });
                    }
                    addMenu.appendChild(kindDiv);
                }
            }
        };
        if (isPc()) {
            this.ele.addEventListener("mouseup", (e) => {
                pX = e.clientX - (WIN_WIDTH * 0.1);
                pY = e.clientY - 90;
                f();
            });
        } else {
            this.ele.addEventListener("touchend", (e) => {
                // 当前触摸的是星期几
                pX = e.changedTouches[0].clientX - (WIN_WIDTH * 0.1);
                pY = e.changedTouches[0].clientY - 90;
                f();
            });
        }
    }

    // _bindResize() {
    //     window.addEventListener("resize", () => {
    //         //
    //         // this.canvasW
    //
    //     });
    // }

    /**
     * 刷新显示 重新绘制
     * 重绘框架，并检测所有时间端，把这一周所有的时间端都画出来
     * 依赖全局变量 userData.periodList
     * 以及 nowWeek
     */
    refresh() {
        this.clear();
        this.drawFrame();
        // 绘制当前所有的时间段
        for (let p of USER_DATA.periodList) {
            if (p.disable) {
                continue;
            }
            // 检测这个段是不是在当前的周里
            for (let dateStr of NOW_WEEK) {
                if (dateStr === p.date) {
                    // 在这周里，开始渲染
                    p.rend(this.ctx, this.canvasW, this.canvasH);
                    break;
                }
            }
        }
    }

    /**
     * 从后端获取用户所有 Period 并刷新
     * 保存到全局变量 userData.periodList 中
     */
    getPeriod() {
        AJAX("userGetAllPeriod", {userName: USER_DATA.name}).finish(res => {
            // 后端的直接覆盖前端
            USER_DATA.periodList = [];
            for (let item of res) {
                let itemObj = TimePeriod.FromJson(item);
                USER_DATA.periodList.push(itemObj);
            }
            this.refresh();
        })
    }

    /**
     * 清除画面
     */
    clear() {
        drawRectFill(this.ctx, 0, 0, this.canvasW, this.canvasH, STYLE[USER_DATA.style].background);
    }

    /**
     * 绘制框架表格
     */
    drawFrame() {
        // 画竖线
        for (let i = 0; i < 7; i++) {
            let x = this.canvasW / 7 * i;
            drawLine(this.ctx, x, 0, x, this.canvasH,
                1, STYLE[USER_DATA.style].normalWord);
        }
        //注意不加单位
        // 画横线
        for (let i = 0; i < HOUR_LIST.length; i++) {
            drawLine(
                this.ctx, 0, i * this.hourHeight, this.canvasW, i * this.hourHeight,
                1, STYLE[USER_DATA.style].dashLine, true
            );
        }

        // 画重要横线
        for (let n of [6, 12]) {
            drawLine(
                this.ctx, 0, n * this.hourHeight, this.canvasW, n * this.hourHeight,
                2, "hotpink", false
            );
        }
    }
}
